package com.example.test.config;

import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Objects;

/**
 * Created by lsl on 2021/2/25.
 */
@Aspect
@Component
public class AopLog {
    @Value("${spring.application.name}")
    private String applicationName;
    @Value("${server.port}")
    private String applicationPort;
    private static final Logger log = LoggerFactory.getLogger(AopLog.class);
    private static final String LOG_TEMPLATE = "${DATA} [ tid: ${TID} ] [ app: ${APP} ] [ reqIp: ${REQ_IP} ] " +
            "[ addr: ${ADDR}:${PORT} ] [ reqUrl: ${REQ_URL} ] [ reqFunc: ${REQ_FUNC} ] [ reqArgs: ${REQ_ARGS} ] [ respTime: ${RESP_TIME} ms ]";

    @Pointcut("execution(* com.example.*.api.impl.*..*(..))")
    private void serviceAspect() {
    }

    @Around("serviceAspect()")
    public Object serviceAround(ProceedingJoinPoint joinPoint) throws Throwable {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String nowDate = format.format(new Date());
        String tid = "";
        String hostAddress = InetAddress.getLocalHost().getHostAddress();
        if (StringUtils.isNotBlank(hostAddress)) {
            String[] ipArr = hostAddress.split("\\.");
            hostAddress = "*.*." + ipArr[2] + "." + ipArr[3];
        }
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String reqIp = "";
        String reqUrl = "";
        if (Objects.nonNull(requestAttributes)) {
            HttpServletRequest request = requestAttributes.getRequest();
            reqIp = this.getIpAddr(request);
            reqUrl = request.getRequestURL().toString();
        }

        Signature signature = joinPoint.getSignature();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();

        String args = Arrays.toString(joinPoint.getArgs());

        Object result;
        long startTime = System.currentTimeMillis();
        result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();

        String printLogStr = LOG_TEMPLATE
                .replaceAll("\\$\\{DATA}", nowDate)
                .replaceAll("\\$\\{TID}", tid)
                .replaceAll("\\$\\{APP}", applicationName)
                .replaceAll("\\$\\{REQ_IP}", reqIp)
                .replaceAll("\\$\\{ADDR}", hostAddress)
                .replaceAll("\\$\\{PORT}", applicationPort)
                .replaceAll("\\$\\{REQ_URL}", reqUrl)
                .replaceAll("\\$\\{REQ_FUNC}", (className + "." + methodName))
                .replaceAll("\\$\\{REQ_ARGS}", args)
                .replaceAll("\\$\\{RESP_TIME}", String.valueOf(endTime - startTime));
        log.info(printLogStr);
        return result;
    }

    /**
     * 获取请求IP地址
     */
    public String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }

        if (ip.split(",").length > 1) {
            ip = ip.split(",")[0];
        }

        return ip;
    }
}